package com.zc.trendsDispatch.task;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.zc.common.constant.RedisKeyConstants;
import com.zc.iotDevice.domain.ChargeStationPile;
import com.zc.iotDevice.mapper.ChargeStationPileMapper;
import com.zc.iotDevice.service.impl.ChargeStationPileServiceImpl;
import com.zc.manager.device.entity.DeviceProperty;
import com.zc.remoteControl.service.RemoteInstructSendService;
import com.zc.trendsDispatch.domain.*;
import com.zc.trendsDispatch.mapper.*;
import com.zc.util.ArithmeticUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.zc.util.ModbusCRC16.calculateCRC;
import static com.zc.util.RadixUtil.*;

/**
 * @Author glb
 * @Date 2024/2/4 17:17
 * @Version 1.0
 */
@Component("ChargeStationStrategyTask")
public class ChargeStationStrategyTask {

    @Autowired
    private ChargeStationStrategyMapper chargeStationStrategyMapper;

    @Autowired
    private ChargeStationStrategyAssociationMapper chargeStationStrategyAssociationMapper;

    @Autowired
    private ChargeStationPileMapper chargeStationPileMapper;

    @Autowired
    private ChargeStationPileServiceImpl chargeStationPileService;

    @Autowired
    private RemoteInstructSendService remoteInstructSendService;

    @Autowired
    private ChargeStationPredictionMapper chargeStationPredictionMapper;

    @Autowired
    private ChargeStationStrategyHistoryMapper chargeStationStrategyHistoryMapper;

    @Autowired
    private ChargeEngineRuleMapper chargeEngineRuleMapper;

    private static  final SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private RedisCache redisCache;

    private static final String functionId="sendInstruct";

    /**
     * 充电桩动态调度
     *
     * */
    public void intelligentDispatching(){
        Date date = new Date();
        List<ChargeStationStrategy> chargeStationStrategies = chargeStationStrategyMapper.selectChargeStationStrategyList(new ChargeStationStrategy());
        for (int i = 0; i < chargeStationStrategies.size(); i++) {
            ChargeEngineRule chargeEngineRule = chargeEngineRuleMapper.selectChargeEngineRuleByRuleId(Long.valueOf(chargeStationStrategies.get(i).getStrategyType()));
            String stationCode = chargeStationStrategies.get(i).getStationCode();
            ChargeStationStrategyAssociation chargeStationStrategyAssociation=new ChargeStationStrategyAssociation();
            chargeStationStrategyAssociation.setStationId(stationCode);
            //场站负载电表列表
            List<ChargeStationStrategyAssociation> chargeStationStrategyAssociations = chargeStationStrategyAssociationMapper.selectChargeStationStrategyAssociationList(chargeStationStrategyAssociation);
            //负载功率
            double countPower=0;
            //变压器容量
            int transformerCapacity = chargeStationStrategies.get(i).getTransformerCapacity();
            //变压器阈值
            int threshold = chargeStationStrategies.get(i).getThreshold();
            for (int i1 = 0; i1 < chargeStationStrategyAssociations.size(); i1++) {
                Object cacheMapValue = redisCache.getCacheMapValue(RedisKeyConstants.STATION_DEVICE_REAL_POWER.replaceAll(":station:device", ":1001:"), chargeStationStrategyAssociations.get(i1).getDeviceId());
                 countPower = ArithmeticUtils.add(countPower, Double.parseDouble(cacheMapValue.toString()));
            }
            //countPower=20;
            //可用阈值（变压器容量-变压器阈值）
            double available = ArithmeticUtils.sub(transformerCapacity, threshold);
            //实际可用负载（可用阈值-负载功率）
            double reality = ArithmeticUtils.sub(available, countPower);
            System.err.println("电表负载："+countPower);
            System.err.println("可用阈值："+available);
            System.err.println("实际可用负载："+reality);
            String ruleContent = chargeEngineRule.getRuleContent();
            int pilePower = chargeEngineRule.getPilePower();
            String adjustType = chargeEngineRule.getAdjustType();
            JSONObject ruleJSONObject = JSONObject.parseObject(ruleContent);
            if (StringUtils.isNotNull((ruleJSONObject))) {
                List<ChargeRuleTrigger> triggers = JSONObject.parseArray(ruleJSONObject.getString("trigger"), ChargeRuleTrigger.class);
                ChargeStationPile chargeStationPile=new ChargeStationPile();
                chargeStationPile.setStationCode(stationCode);
                chargeStationPile.setStatus("1");
                List<ChargeStationPile> listPile = chargeStationPileService.getList(chargeStationPile);
                Dynamic(listPile,countPower,reality,date,"1",triggers,pilePower,adjustType);
            }
        }
    }


    /**
     * 充电桩预测调度
     * */
    public void predictionDistribute() throws ParseException {
        Date date = new Date();
        SimpleDateFormat dateFormat= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat year= new SimpleDateFormat("yyyy-MM-dd");
        String format = dateFormat.format(date);
        //format="2024-02-28";
        String substring = format.substring(11, 16);
        System.out.println("时间："+format);
        System.out.println("时间小时："+substring);
        if("0".equals(substring.substring(0,1))){
            substring=substring.substring(1);
        }
        //substring="16:40";
        ChargeStationPrediction chargeStationPrediction=new ChargeStationPrediction();
        chargeStationPrediction.setForecastDate(year.parse(format.substring(0,10)));
        //预测列表
        List<ChargeStationPrediction> chargeStationPredictions = chargeStationPredictionMapper.selectChargeStationPredictionList(chargeStationPrediction);
        for (int i = 0; i < chargeStationPredictions.size(); i++) {
            //预测值
            String forecastValue = chargeStationPredictions.get(i).getForecastValue();
            JSONObject jsonObject = JSONObject.parseObject(forecastValue);
            Map<String, Object> personMap = BeanUtil.beanToMap(jsonObject.get(substring));
            //取出当前时间段预测变化值
            String change= String.valueOf(personMap.get("change"));
            ChargeStationStrategyAssociation chargeStationStrategyAssociation=new ChargeStationStrategyAssociation();
            chargeStationStrategyAssociation.setStationId(chargeStationPredictions.get(i).getStationCode());
            //场站负载电表列表
            List<ChargeStationStrategyAssociation> chargeStationStrategyAssociationsList = chargeStationStrategyAssociationMapper.selectChargeStationStrategyAssociationList(chargeStationStrategyAssociation);
            //负载功率
            double countPower=0;
            for (int j = 0; j < chargeStationStrategyAssociationsList.size(); j++) {
                Object cacheMapValue = redisCache.getCacheMapValue(RedisKeyConstants.STATION_DEVICE_REAL_POWER.replaceAll(":station:device", ":1001:"), chargeStationStrategyAssociationsList.get(i).getDeviceId());
                countPower = ArithmeticUtils.add(countPower, Double.parseDouble(cacheMapValue.toString()));
            }
            personMap.put("reality",countPower);
            jsonObject.put(substring,personMap);
            chargeStationPredictions.get(i).setForecastValue(jsonObject.toJSONString());
            //更新预测实际实时数据
            int updateChargeStationPrediction = chargeStationPredictionMapper.updateChargeStationPrediction(chargeStationPredictions.get(i));
            System.err.println("负载功率："+countPower);
            System.err.println("数值变化："+change);
            System.err.println("预测值："+personMap.get("value"));
            System.err.println("包边值："+personMap.get("max"));
            if("1".equals(change)){
                //包边值
                int max= Integer.parseInt(String.valueOf(personMap.get("max")));
                String stationCode = chargeStationPredictions.get(i).getStationCode();
                //查询场站策略列表
                List<ChargeStationStrategy> chargeStationStrategies = chargeStationStrategyMapper.selectChargeStationStrategyListByCode(stationCode);
                if(chargeStationStrategies.size()>0){
                    ChargeStationStrategy chargeStationStrategy = chargeStationStrategies.get(0);
                    //规则ID
                    int strategyType = chargeStationStrategy.getStrategyType();
                    ChargeEngineRule chargeEngineRule = chargeEngineRuleMapper.selectChargeEngineRuleByRuleId(Long.valueOf(chargeStationStrategies.get(i).getStrategyType()));
                    String ruleContent = chargeEngineRule.getRuleContent();
                    int pilePower = chargeEngineRule.getPilePower();
                    String adjustType = chargeEngineRule.getAdjustType();
                    JSONObject ruleJSONObject = JSONObject.parseObject(ruleContent);
                    if (StringUtils.isNotNull((ruleJSONObject))) {
                        List<ChargeRuleTrigger> triggers = JSONObject.parseArray(ruleJSONObject.getString("trigger"), ChargeRuleTrigger.class);
                        //变压器容量
                        int transformerCapacity = chargeStationStrategy.getTransformerCapacity();
                        //阈值
                        int threshold = chargeStationStrategy.getThreshold();
                        //变压器容量-阈值=可用容量
                        double available = ArithmeticUtils.sub(transformerCapacity, threshold);
                        //可用容量-预测包边值=充电桩可分配值
                        double reality = ArithmeticUtils.sub(available, max);
                        //可用容量-场站功率=充电桩可分配值
                        double realitys = ArithmeticUtils.sub(available, countPower);
                        ChargeStationPile chargeStationPile=new ChargeStationPile();
                        chargeStationPile.setStationCode(stationCode);
                        //根据场站查询充电桩数
                        List<ChargeStationPile> listPile = chargeStationPileService.getList(chargeStationPile);
                        Dynamic(listPile,countPower,reality,date,"2",triggers,pilePower,adjustType);
                    }
                }
            }
        }
    }


    /**
     * countPower场站实时功率  reality 可分配功率  date 触发时间  dispatchType触发类型（1动态2预测） triggers 策略列表 pilePower充电桩功率 adjustType(1百分百 2实际值)
     * 动态调节
     * */
    public void Dynamic(List<ChargeStationPile> listPile,double countPower,double reality,Date date,String dispatchType,List<ChargeRuleTrigger> triggers,int pilePower,String adjustType){
        ChargeStationPile chargeStationPile = listPile.get(0);
        //启用
        int enable=0;
        List<String> enableList=new ArrayList<>();
        //停用
        int deactivate=0;
        //空闲
        int idle=0;
        List<String> idleList=new ArrayList<>();
        //使用
        int use=0;
        List<String> useList=new ArrayList<>();
        //离线/故障
        int offline=0;
        for (int i = 0; i < listPile.size(); i++) {
            if("1".equals(listPile.get(i).getStatus())){
                enable=enable+1;
                enableList.add(listPile.get(i).getDeviceId());
                if("1".equals(listPile.get(i).getServiceStatus())){
                    idle=idle+1;
                    idleList.add(listPile.get(i).getDeviceId());
                }else if("2".equals(listPile.get(i).getServiceStatus())){
                    use=use+1;
                    useList.add(listPile.get(i).getDeviceId());
                }else{
                    offline=offline+1;
                }
            }else{
                deactivate=deactivate+1;
            }
        }
        //最小功率值
        int min = triggers.stream().filter(t -> t.getSettingValue() > 0).min(Comparator.comparingInt(ChargeRuleTrigger::getSettingValue)).get().getSettingValue();
        if("1".equals(adjustType)){
            min=(int) ArithmeticUtils.div(ArithmeticUtils.mul(pilePower,min),100);
        }
        //16进制最小功率值
        String hexadecimal = intHECToHex(min);
        //启用最低功率值
        double enableMul = ArithmeticUtils.mul(enable, min);
        //空闲最低功率值
        double idleMul = ArithmeticUtils.mul(idle, min);
        //使用最低功率值
        double useMul = ArithmeticUtils.mul(use, min);
        //充电桩启用最低负载 大于 场站剩余负载
        if(enableMul>reality){
            //场站剩余负载可供给数
            double available = ArithmeticUtils.div(reality, min);
            int rounding=(int) available;
            //最低负载可支持使用中
            if(rounding>=use){
                //可供给空闲数
                int sub =rounding-use;
                //总-能用=停用
                for (int i = 0; i <idleList.size()-sub; i++) {
                    String deviceCode = idleList.get(i);
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, hexadecimal, min, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*停用命令*/
                    adjustPowerCommand(deviceCode, hexadecimal,"01",assemble,pilePower,adjustType);
                }
                for (int i = idleList.size()-sub; i < idleList.size(); i++) {
                    String deviceCode = idleList.get(i);
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, hexadecimal, min, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*启用最低命令*/
                    adjustPowerCommand(deviceCode, hexadecimal,"00",assemble,pilePower,adjustType);
                }
                for (int i = 0; i < useList.size(); i++) {
                    String deviceCode = useList.get(i);
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, hexadecimal, min, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*启用最低命令*/
                    adjustPowerCommand(deviceCode, hexadecimal,"00",assemble,pilePower,adjustType);
                }
            }else{
                //场站剩余负载可供给数<充电中
                //空闲全部停用
                for (int i = 0; i <idleList.size(); i++) {
                    String deviceCode = idleList.get(i);
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, hexadecimal,min, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*停用命令*/
                    adjustPowerCommand(deviceCode, hexadecimal,"01",assemble,pilePower,adjustType);
                }
                int withstand= use-rounding;
                //启用可启用最低数
                for (int i = useList.size()-withstand; i < useList.size(); i++) {
                    String deviceCode = useList.get(i);
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, hexadecimal, min, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*启用最低命令*/
                    adjustPowerCommand(deviceCode, hexadecimal,"00",assemble,pilePower,adjustType);
                }
                //启用可停用数
                for (int i = 0; i < useList.size()-withstand; i++) {
                    String deviceCode = useList.get(i);
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, hexadecimal, min, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*启用最低命令*/
                    adjustPowerCommand(deviceCode, hexadecimal,"01",assemble,pilePower,adjustType);
                }
            }
        //充电桩启用最低负载 小于 场站剩余负载
        }else{
            //存在使用中
            if(use>0){
                //场站剩余-空闲最低占用=可用容量
                double useIdle = ArithmeticUtils.sub(reality, idleMul);
                //可用容量/使用桩数=使用中可调
                double adjustable = ArithmeticUtils.div(useIdle, use);
                String setValue = conversion(triggers, adjustable);
                int setValueInt = Integer.parseInt(hexToDecimal(setValue));
                for (String deviceCode : idleList) {
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, hexadecimal, min, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*空闲最低命令*/
                    adjustPowerCommand(deviceCode, hexadecimal,"00",assemble,pilePower,adjustType);
                }
                for (String deviceCode : useList) {
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, setValue, setValueInt, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*使用适配命令*/
                    adjustPowerCommand(deviceCode, setValue,"00",assemble,pilePower,adjustType);
                }
            //全部空闲
            }else{
                //可用容量/空闲桩数=空闲中可调
                double adjustable = ArithmeticUtils.div(reality, idle);
                String setValue = conversion(triggers, adjustable);
                int setValueInt = Integer.parseInt(hexToDecimal(setValue));
                for (String deviceCode : idleList) {
                    ChargeStationStrategyHistory assemble = assemble(chargeStationPile.getStationCode(), deviceCode, date, setValue, setValueInt, dispatchType, String.valueOf(countPower), String.valueOf(reality));
                    /*使用适配命令*/
                    adjustPowerCommand(deviceCode, setValue,"00",assemble,pilePower,adjustType);
                }
            }

        }
    }




    /**
     * 调整功率命令组装下发
     * */
    public void  adjustPowerCommand(String deviceCode,String setValue,String lock,ChargeStationStrategyHistory chargeStationStrategyHistory,int pilePower,String adjustType){
        String reply ="680D00000052"+deviceCode+lock+setValue;
        String validation = Validation(reply);
        reply=reply+validation;
        Map<String, Object> props =new HashMap<>();
        props.put("message",reply);
        System.err.println("下发的设备："+deviceCode);
        System.err.println("下发的指令："+reply);
        chargeStationStrategyHistory.setSetMessage(reply);
        Map<String, DeviceProperty> realData = remoteInstructSendService.getRealData(deviceCode);
        String unit="";
        if(realData.containsKey("maxPower")){
            double AStatic = Double.parseDouble(String.valueOf(realData.get("maxPower").getValue()));
            int AStaticInt=(int)AStatic;
            int maxPower=0;
            if("1".equals(adjustType)){
                maxPower=(int) ArithmeticUtils.div(ArithmeticUtils.mul(pilePower,chargeStationStrategyHistory.getMaxPower()),100);
                unit="%";
            }else {
                maxPower=chargeStationStrategyHistory.getMaxPower();
                unit="Kw";
            }
            //maxPower=240;
            System.err.println("设置功率值："+maxPower+"实际功率值："+AStaticInt);
            if(maxPower == AStaticInt){
                return;
            }
        }
        remoteInstructSendService.sendMessage(deviceCode,functionId,props);
        if("01".equals(lock)){
            chargeStationStrategyHistory.setDispatchContent("设备编号："+deviceCode+chargeStationStrategyHistory.getDispatchName()+"可分配功率不足最低功率，已暂时设置停机。");
        }else{
            chargeStationStrategyHistory.setDispatchContent("设备编号："+deviceCode+chargeStationStrategyHistory.getDispatchName()+"设置功率为"+chargeStationStrategyHistory.getMaxPower()+unit+"。");
        }
        chargeStationStrategyHistoryMapper.insertChargeStationStrategyHistory(chargeStationStrategyHistory);
    }





    /**
     * 策略匹配
     * @param triggers 策略列表
     * @param reality 分配值
     * */
    public static String conversion(List<ChargeRuleTrigger> triggers, double reality){
        for (int i = 0; i < triggers.size(); i++) {
            String operator="";
            if(triggers.get(i).getConditionType()==1){
                operator= String.valueOf(triggers.get(i).getComparePatternFrontType());
            }else{
                 operator=triggers.get(i).getComparePatternFrontType()+""+triggers.get(i).getComparePatternAfterType();
            }
            boolean compare = compare(triggers.get(i).getCompareFrontValue(), triggers.get(i).getCompareAfterValue(), reality, operator);
            if(compare){
                int settingValue = triggers.get(i).getSettingValue();
                String hexadecimal = intHECToHex(settingValue);
                System.err.println("设置为："+settingValue+"转换后："+hexadecimal);
                return hexadecimal;
            }
        }
        return null;

    }

    /**
     * 比较符
     * (0:>；1:>=；2:<；3:<=；4:==；5:!=；6:in；7:between；)
     * >=|< 12  >=|<= 13  1>=
     * */
    public static boolean compare(double front, double after,double value, String operator) {
        switch (operator) {
            case "12":
                return front<=value&&value<after;
            case "13":
                return front<=value&&value<=after;
            case "1":
                return front<=value;
            // 添加其他你需要的比较运算符
            default:
                return false;
        }
    }


    /**
     * 功率适配
     * */
    public String  matchingValue(double reality){
        String setValue="";
        if(reality>36&&reality<60){
            setValue="1E";
            System.err.println("充电桩功率设置为30%,实际功率为36KW");
        }else if(reality>60&&reality<84){
            setValue="32";
            System.err.println("充电桩功率设置为50%,实际功率为60KW");
        }else if(reality>84&&reality<120){
            setValue="46";
            System.err.println("充电桩功率设置为70%,实际功率为84KW");
        }else if(reality>120){
            setValue="64";
            System.err.println("充电桩功率设置为100%,实际功率为120KW");
        }
        return setValue;
    }

    /**
     * 实体组装
     * */
    public ChargeStationStrategyHistory assemble(String stationCode,String deviceId,Date dispatchTime,String setValue,
                                                 int maxPower,String dispatchType,String stationRealPower,String allocationPower){
        ChargeStationStrategyHistory chargeStationStrategyHistory=new ChargeStationStrategyHistory();
        chargeStationStrategyHistory.setStationCode(stationCode);
        chargeStationStrategyHistory.setDeviceId(deviceId);
        chargeStationStrategyHistory.setDispatchTime(dispatchTime);
        chargeStationStrategyHistory.setSetValue(setValue);
        chargeStationStrategyHistory.setMaxPower(maxPower);
        chargeStationStrategyHistory.setDispatchType(dispatchType);
        chargeStationStrategyHistory.setStationRealPower(stationRealPower);
        chargeStationStrategyHistory.setAllocationPower(allocationPower);
        if("1".equals(dispatchType)){
            chargeStationStrategyHistory.setDispatchName("动态调度");
        }else{
            chargeStationStrategyHistory.setDispatchName("预测调度");
        }
        return chargeStationStrategyHistory;

    }

    /**
     * 数据效验
     * */
    public static String Validation(String data){
        String substring = data.substring(4);
        byte[] message= hexToByte(substring);
        String crcValidation = intHECToHex(calculateCRC(message));
        return crcValidation;
    }






}
